package com.peas.platform.module.icims.expenditure.kpis.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import com.peas.platform.common.core.enums.BaseEnum;
import com.peas.platform.framework.mybatisplus.domain.BaseDomain;
import com.peas.platform.framework.mybatisplus.po.BasePo;
import com.peas.platform.framework.mybatisplus.service.BaseServiceImpl;
import com.peas.platform.module.icims.base.approve.component.ApproveCallback;
import com.peas.platform.module.icims.base.approve.dto.ApproveDto;
import com.peas.platform.module.icims.base.approve.dto.ApproveOrderNodeDto;
import com.peas.platform.module.icims.base.approve.enums.ApproveOrderBusinessType;
import com.peas.platform.module.icims.base.approve.service.ApproveOrderService;
import com.peas.platform.module.icims.base.approve.service.ApproveService;
import com.peas.platform.module.icims.base.sys.enums.CommonYesNo;
import com.peas.platform.module.icims.expenditure.expenses.dto.ExpenditureApplicationDto;
import com.peas.platform.module.icims.expenditure.expenses.dto.ExpenditureReimbursementDto;
import com.peas.platform.module.icims.expenditure.expenses.enums.ExpenditureApplicationState;
import com.peas.platform.module.icims.expenditure.expenses.enums.ExpenditureReimbursementState;
import com.peas.platform.module.icims.expenditure.expenses.service.ExpenditureApplicationService;
import com.peas.platform.module.icims.expenditure.expenses.service.ExpenditureReimbursementService;
import com.peas.platform.module.icims.expenditure.initialize.dto.ExpenditureInitQuotaDto;
import com.peas.platform.module.icims.expenditure.initialize.dto.ExpenditureInitReimbursementDto;
import com.peas.platform.module.icims.expenditure.initialize.service.ExpenditureInitQuotaService;
import com.peas.platform.module.icims.expenditure.initialize.service.ExpenditureInitReimbursementService;
import com.peas.platform.module.icims.expenditure.kpis.api.req.SaveExpenditureKpiVo;
import com.peas.platform.module.icims.expenditure.kpis.api.req.SubmitExpenditureKpiVo;
import com.peas.platform.module.icims.expenditure.kpis.controller.vo.ExpenditureKpiItemVo;
import com.peas.platform.module.icims.expenditure.kpis.domain.ExpenditureKpiDomain;
import com.peas.platform.module.icims.expenditure.kpis.dto.*;
import com.peas.platform.module.icims.expenditure.kpis.enums.ExpenditureAdjustmentState;
import com.peas.platform.module.icims.expenditure.kpis.enums.ExpenditureKpiState;
import com.peas.platform.module.icims.expenditure.kpis.enums.ExpenditureQuotaState;
import com.peas.platform.module.icims.expenditure.kpis.service.*;
import com.peas.platform.module.icims.expenditure.setting.dto.ExpenditureSettingsDto;
import com.peas.platform.module.icims.expenditure.setting.enums.ExpenditureSettingsType;
import com.peas.platform.module.icims.expenditure.setting.service.ExpenditureSettingsService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicReference;

@Service
@Slf4j
public class ExpenditureKpiServiceImpl extends BaseServiceImpl<ExpenditureKpiDto> implements ExpenditureKpiService, ApproveCallback {

    @Resource
    private ExpenditureKpiDomain expenditureKpiDomain;
    @Resource
    private ExpenditureKpiItemService expenditureKpiItemService;
    @Resource
    private ApproveService approveService;
    @Resource
    private ApproveOrderService approveOrderService;
    @Resource
    private ExpenditureSettingsService expenditureSettingsService;
    @Resource
    private ExpenditureAdjustmentService expenditureAdjustmentService;
    @Resource
    private ExpenditureAdjustmentItemService expenditureAdjustmentItemService;
    @Resource
    private ExpenditureQuotaService expenditureQuotaService;
    @Resource
    private ExpenditureInitQuotaService expenditureInitQuotaService;
    @Resource
    private ExpenditureInitReimbursementService expenditureInitReimbursementService;
    @Resource
    private ExpenditureApplicationService expenditureApplicationService;
    @Resource
    private ExpenditureReimbursementService expenditureReimbursementService;

    @Override
    public BaseDomain<ExpenditureKpiDto, ? extends BasePo> getDomain() {
        return expenditureKpiDomain;
    }

    @Transactional
    @Override
    public ExpenditureKpiDto saveExpenditureKpi(SaveExpenditureKpiVo vo) {
        ExpenditureKpiDto ekd = BeanUtil.copyProperties(vo, ExpenditureKpiDto.class);
        if (StrUtil.isBlank(ekd.getState())) {
            ekd.setState(ExpenditureKpiState.save.getKey());
        }
        Assert.isTrue(ekd.getAmount().compareTo(BigDecimal.ZERO) > 0, "预算总金额必须大于0");
        int result;
        if (vo.getId() != null) {
            ExpenditureKpiDto bean = this.getById(vo.getId());
            ExpenditureKpiState state = BaseEnum.key2Enum(ExpenditureKpiState.class, bean.getState());
            Assert.isTrue(ExpenditureKpiState.save == state || ExpenditureKpiState.revocation == state || ExpenditureKpiState.reject == state, "指标单[" + bean.getKpiCode() + "]的状态为[" + state.getKey() + "-" + state.getValue() + "]，不允许修改");
            result = this.updateById(ekd);
        } else {
            result = this.save(ekd);
        }
        Assert.isTrue(result > 0, "保存失败");
        List<ExpenditureKpiItemDto> ekids = expenditureKpiItemService.listByField("expenditureKpiId", ekd.getId());
        expenditureKpiItemService.removeBatchByList(ekids);
        // items
        if (StrUtil.equals(CommonYesNo.yes.getKey(), ekd.getIsEconomic())) {
            ConcurrentLinkedQueue<String> expenditureEconomicIds = new ConcurrentLinkedQueue<>();
            if (CollUtil.isNotEmpty(vo.getItems())) {
                List<ExpenditureKpiItemDto> ekidList = new ArrayList<>();
                CollUtil.forEach(vo.getItems(), (CollUtil.Consumer<ExpenditureKpiItemVo>) (value, index) -> {
                    Assert.notBlank(value.getExpenditureEconomicId(), "请选择经济分类");
                    Assert.notNull(value.getAmount(), "金额不能为空");
                    Assert.isTrue(value.getAmount().compareTo(BigDecimal.ZERO) > 0, "金额必须大于0");
                    ExpenditureKpiItemDto dto = BeanUtil.copyProperties(value, ExpenditureKpiItemDto.class);
                    dto.setExpenditureKpiId(ekd.getId());
                    ekidList.add(dto);
                    Assert.isTrue(!expenditureEconomicIds.contains(dto.getExpenditureEconomicId()), "经济分类不能重复");
                    expenditureEconomicIds.add(dto.getExpenditureEconomicId());
                });
                expenditureKpiItemService.saveBatch(ekidList);
            }
        }
        return ekd;
    }

    @Transactional
    @Override
    public void submitExpenditureKpi(SubmitExpenditureKpiVo vo) {
        Assert.notNull(vo.getApproveId(), "请选择审批模版");
        SaveExpenditureKpiVo v = BeanUtil.copyProperties(vo, SaveExpenditureKpiVo.class);
        v.setState(ExpenditureKpiState.submit.getKey());
        v.setItems(vo.getItems());
        ExpenditureKpiDto ead = this.saveExpenditureKpi(v);
        ApproveDto ad = approveService.getById(vo.getApproveId());
        approveOrderService.createApproveOrder(ad, BeanUtil.copyToList(vo.getApproveNodes(), ApproveOrderNodeDto.class), ApproveOrderBusinessType.expenditureKpi, ead.getId(), ead.getKpiCode(), null, this.getClass());
    }

    @Transactional
    @Override
    public void revocationExpenditureKpi(Long id) {
        ExpenditureKpiDto dto = this.getById(id);
        Assert.notNull(dto, "找不到指标单");
        dto.setState(ExpenditureKpiState.revocation.getKey());
        this.updateById(dto);
        approveOrderService.revocationApproveOrder(ApproveOrderBusinessType.expenditureKpi, id);
    }

    // 总调整金额
    @Override
    public BigDecimal getTotalAdjustmentAmount(final Long expenditureKpiId) {
        Assert.notNull(expenditureKpiId, "指标单ID不能为空");
        BigDecimal totalAdjustmentAmount;
        AtomicReference<BigDecimal> total = new AtomicReference<>(BigDecimal.ZERO);
        List<ExpenditureAdjustmentDto> list = expenditureAdjustmentService.listByField("expenditureKpiId", expenditureKpiId);
        CollUtil.forEach(list, (CollUtil.Consumer<ExpenditureAdjustmentDto>) (value, index) -> {
            if (value.getAdjustAmount().compareTo(BigDecimal.ZERO) >= 0) {
                // 加金额
                String[] states = {
                        ExpenditureAdjustmentState.pass.getKey(),
                };
                if (ArrayUtil.contains(states, value.getState())) {
                    total.compareAndSet(total.get(), total.get().add(value.getAdjustAmount()));
                }
            } else {
                // 减金额
                String[] states = {
                        ExpenditureAdjustmentState.submit.getKey(),
                        ExpenditureAdjustmentState.pass.getKey(),
                };
                if (ArrayUtil.contains(states, value.getState())) {
                    total.compareAndSet(total.get(), total.get().add(value.getAdjustAmount()));
                }
            }
        });
        list.forEach(value -> {

        });
        totalAdjustmentAmount = total.get();
        return totalAdjustmentAmount;
    }

    // 总下达金额
    @Override
    public BigDecimal getTotalQuotaAmount(final Long expenditureKpiId) {
        Assert.notNull(expenditureKpiId, "指标单ID不能为空");
        BigDecimal totalQuotaAmount;
        AtomicReference<BigDecimal> total = new AtomicReference<>(BigDecimal.ZERO);
        List<ExpenditureQuotaDto> list = expenditureQuotaService.listByField("expenditureKpiId", expenditureKpiId);
        log.info("ExpenditureQuotaDto list:" + list);
        CollUtil.forEach(list, (CollUtil.Consumer<ExpenditureQuotaDto>) (value, index) -> {
            // 下达是加金额
            String[] states = {
                    ExpenditureQuotaState.pass.getKey(),
            };
            if (ArrayUtil.contains(states, value.getState())) {
                total.compareAndSet(total.get(), total.get().add(value.getAmount()));
            }
        });
        list.forEach(value -> {
        });
        List<ExpenditureInitQuotaDto> listInit = expenditureInitQuotaService.listByField("expenditureKpiId", expenditureKpiId);
        log.info("ExpenditureInitQuotaDto list:" + listInit);
        CollUtil.forEach(listInit, (CollUtil.Consumer<ExpenditureInitQuotaDto>) (value, index) -> total.compareAndSet(total.get(), total.get().add(value.getAmount())));
        totalQuotaAmount = total.get();
        return totalQuotaAmount;
    }

    // 总申请金额
    @Override
    public BigDecimal getTotalApplicationAmount(final Long expenditureKpiId) {
        Assert.notNull(expenditureKpiId, "指标单ID不能为空");
        BigDecimal totalApplicationAmount;
        AtomicReference<BigDecimal> total = new AtomicReference<>(BigDecimal.ZERO);
        List<ExpenditureApplicationDto> list = expenditureApplicationService.listByField("expenditureKpiId", expenditureKpiId);
        log.info("ExpenditureApplicationDto list:" + list);
        CollUtil.forEach(list, (CollUtil.Consumer<ExpenditureApplicationDto>) (value, index) -> {
            // 申请是减金额
            String[] states = {
                    ExpenditureApplicationState.submit.getKey(),
                    ExpenditureApplicationState.pass.getKey(),
            };
            if (ArrayUtil.contains(states, value.getState())) {
                total.compareAndSet(total.get(), total.get().add(value.getAmount()));
            }
        });
        totalApplicationAmount = total.get();
        return totalApplicationAmount;
    }

    // 总报账金额
    @Override
    public BigDecimal getTotalReimbursementAmount(final Long expenditureKpiId) {
        Assert.notNull(expenditureKpiId, "指标单ID不能为空");
        BigDecimal totalReimbursementAmount;
        AtomicReference<BigDecimal> total = new AtomicReference<>(BigDecimal.ZERO);
        List<ExpenditureReimbursementDto> list = expenditureReimbursementService.listByField("expenditureKpiId", expenditureKpiId);
        log.info("ExpenditureReimbursementDto list:" + list);
        CollUtil.forEach(list, (CollUtil.Consumer<ExpenditureReimbursementDto>) (value, index) -> {
            // 报账是减金额
            String[] states = {
                    ExpenditureReimbursementState.submit.getKey(),
                    ExpenditureReimbursementState.pass.getKey(),
                    ExpenditureReimbursementState.complete.getKey(),
                    ExpenditureReimbursementState.paying.getKey(),
                    ExpenditureReimbursementState.confirm.getKey(),
            };
            if (ArrayUtil.contains(states, value.getState())) {
                total.compareAndSet(total.get(), total.get().add(value.getAmount()));
            }
        });
        List<ExpenditureInitReimbursementDto> listInit = expenditureInitReimbursementService.listByField("expenditureKpiId", expenditureKpiId);
        log.info("ExpenditureInitReimbursementDto list:" + listInit);
        CollUtil.forEach(listInit, (CollUtil.Consumer<ExpenditureInitReimbursementDto>) (value, index) -> total.compareAndSet(total.get(), total.get().add(value.getAmount())));
        totalReimbursementAmount = total.get();
        return totalReimbursementAmount;
    }

    @Override
    public BigDecimal queryAvailableAmount(Long expenditureKpiId) {
        Assert.notNull(expenditureKpiId, "请选择指标单");
        ExpenditureKpiDto dto = this.getById(expenditureKpiId);
        Assert.notNull(dto, "指标单不能为空");
        Assert.notNull(dto.getId(), "指标单不能为空");
        if (StrUtil.equals(ExpenditureKpiState.save.getKey(), dto.getState()) || StrUtil.equals(ExpenditureKpiState.submit.getKey(), dto.getState()) || StrUtil.equals(ExpenditureKpiState.reject.getKey(), dto.getState()) || StrUtil.equals(ExpenditureKpiState.revocation.getKey(), dto.getState())) {
            return BigDecimal.ZERO;
        }
        // 总指标金额
        BigDecimal totalKpiAmount = dto.getAmount();
        // 总调整金额
        BigDecimal totalAdjustmentAmount = this.getTotalAdjustmentAmount(dto.getId());
        // 总下达金额
        BigDecimal totalQuotaAmount = this.getTotalQuotaAmount(dto.getId());
        // 总申请金额
        // BigDecimal totalApplicationAmount = this.getTotalApplicationAmount(dto.getId());
        // 总报账金额
        // BigDecimal totalReimbursementAmount = this.getTotalReimbursementAmount(dto.getId());
        // 指标单可用金额
        BigDecimal available;
        final AtomicReference<BigDecimal> sub1 = new AtomicReference<>(BigDecimal.ZERO);// 所有未完成申请单金额
        final AtomicReference<BigDecimal> sub2 = new AtomicReference<>(BigDecimal.ZERO);// 所有未关联申请单的报账金额
        final AtomicReference<BigDecimal> sub3 = new AtomicReference<>(BigDecimal.ZERO);// 所有关联完成的申请单的报账金额
        final AtomicReference<BigDecimal> sub4 = new AtomicReference<>(BigDecimal.ZERO);// 所有初始报账金额
        // sub1
        List<ExpenditureApplicationDto> eads = expenditureApplicationService.listByField("expenditureKpiId", dto.getId());
        CopyOnWriteArrayList<Long> completedAppIds = new CopyOnWriteArrayList<>();
        CollUtil.forEach(eads, (CollUtil.Consumer<ExpenditureApplicationDto>) (value, index) -> {
            //0保存、1提交审批、2审批通过、3审批驳回、4撤回、5完成
            String[] states1 = {
                    ExpenditureApplicationState.submit.getKey(),
                    ExpenditureApplicationState.pass.getKey(),
            };
            if (ArrayUtil.contains(states1, value.getState())) {
                sub1.compareAndSet(sub1.get(), sub1.get().add(value.getAmount()));
            }
            String[] states2 = {
                    ExpenditureApplicationState.complete.getKey(),
            };
            if (ArrayUtil.contains(states2, value.getState())) {
                completedAppIds.add(value.getId());
            }
        });
        // sub2,sub3
        List<ExpenditureReimbursementDto> erds = expenditureReimbursementService.listByField("expenditureKpiId", dto.getId());
        CollUtil.forEach(erds, (CollUtil.Consumer<ExpenditureReimbursementDto>) (value, index) -> {
            //0保存、1提交审批、2审批通过、3审批驳回、4撤回、7完成、5支付中、6确认付款
            String[] states = {
                    ExpenditureReimbursementState.submit.getKey(),
                    ExpenditureReimbursementState.pass.getKey(),
                    ExpenditureReimbursementState.complete.getKey(),
                    ExpenditureReimbursementState.paying.getKey(),
                    ExpenditureReimbursementState.confirm.getKey(),
            };
            if (ArrayUtil.contains(states, value.getState())) {
                if (value.getExpenditureApplicationId() == null) {
                    sub2.compareAndSet(sub2.get(), sub2.get().add(value.getAmount()));
                }
                if (value.getExpenditureApplicationId() != null
                        && CollUtil.contains(completedAppIds, value.getExpenditureApplicationId())) {
                    sub3.compareAndSet(sub3.get(), sub3.get().add(value.getAmount()));
                }
            }
        });
        // sub4
        List<ExpenditureInitReimbursementDto> eirds = expenditureInitReimbursementService.listByField("expenditureKpiId", dto.getId());
        CollUtil.forEach(eirds, (CollUtil.Consumer<ExpenditureInitReimbursementDto>) (value, index) -> sub4.compareAndSet(sub4.get(), sub4.get().add(value.getAmount())));

        List<ExpenditureSettingsDto> esds = expenditureSettingsService.getExpenditureSettingsDto(ExpenditureSettingsType.values());
        ExpenditureSettingsDto quotaControl = esds.stream().filter(bean -> bean.getSettingsType().equals(ExpenditureSettingsType.quotaControl.getKey())).findFirst().orElse(null);
        if (quotaControl != null && StrUtil.equals(CommonYesNo.yes.getKey(), quotaControl.getSettingsValue())) {
            // 启用额度下达控制：下达金额 - 未完成的申请单金额 - 未关联申请单的报账单金额 - 完成的申请单下报账单金额 - 初始报账金额
            available = totalQuotaAmount.subtract(sub1.get()).subtract(sub2.get()).subtract(sub3.get()).subtract(sub4.get());
        } else {
            // 不启用额度下达控制
            available = totalKpiAmount.add(totalAdjustmentAmount).subtract(sub1.get()).subtract(sub2.get()).subtract(sub3.get()).subtract(sub4.get());
        }
        return available;
    }

    @Override
    public BigDecimal queryAvailableAmount(Long expenditureKpiId, String expenditureEconomicIdStr, final boolean useFluctuate) {
        Assert.notNull(expenditureKpiId, "请选择指标单");
        Assert.notBlank(expenditureEconomicIdStr, "请选择经济分类");
        ExpenditureKpiDto dto = this.getById(expenditureKpiId);
        Assert.equals(CommonYesNo.yes.getKey(), dto.getIsEconomic(), "指标单必须是按经济分类控制金额");
        Assert.notNull(dto, "指标单不能为空");
        Assert.notNull(dto.getId(), "指标单不能为空");
        // 指标单经济分类可用金额
        String[] unsupport = {
                ExpenditureKpiState.save.getKey(),
                ExpenditureKpiState.submit.getKey(),
                ExpenditureKpiState.reject.getKey(),
                ExpenditureKpiState.revocation.getKey(),
        };
        if (ArrayUtil.contains(unsupport, dto.getState())) {
            return BigDecimal.ZERO;
        }
        Assert.equals(dto.getIsEconomic(), CommonYesNo.yes.getKey(), "指标单[" + dto.getKpiCode() + "]没有开启按经济分类控制金额");
        List<ExpenditureKpiItemDto> items = expenditureKpiItemService.listByField("expenditureKpiId", dto.getId());
        ExpenditureKpiItemDto item = items.stream().filter(bean -> bean.getExpenditureEconomicId().equals(expenditureEconomicIdStr)).findFirst().orElse(null);
        Assert.notNull(item, "指标单[" + dto.getKpiCode() + "]没有选定的经济分类明细");
        assert item != null;

        final AtomicReference<BigDecimal> available = new AtomicReference<>(item.getAmount());//
        log.info("available value1:" + available.get());
        // 调整单有明细，取最后一条调整单的浮动率
        BigDecimal fluctuate = item.getFluctuate();
        List<ExpenditureAdjustmentDto> adjusts = expenditureAdjustmentService.listByField("expenditureKpiId", dto.getId());
        if (CollUtil.isNotEmpty(adjusts)) {
            List<Long> expenditureAdjustmentIds = new ArrayList<>();
            adjusts.forEach(v -> expenditureAdjustmentIds.add(v.getId()));
            List<ExpenditureAdjustmentItemDto> adjustItems = expenditureAdjustmentItemService.listByField("expenditureAdjustmentId", expenditureAdjustmentIds);
            if (CollUtil.isNotEmpty(adjustItems)) {
                ExpenditureAdjustmentItemDto last = null;
                for (ExpenditureAdjustmentDto adjust : adjusts) {
                    for (ExpenditureAdjustmentItemDto adjustItem : adjustItems) {
                        if (!adjust.getId().equals(adjustItem.getExpenditureAdjustmentId())) {
                            continue;
                        }
                        if (!StrUtil.equals(expenditureEconomicIdStr, adjustItem.getExpenditureEconomicId())) {
                            continue;
                        }
                        if (adjustItem.getAdjustAmount().compareTo(BigDecimal.ZERO) >= 0) {
                            // 加金额
                            String[] states = {
                                    ExpenditureAdjustmentState.pass.getKey(),
                            };
                            if (ArrayUtil.contains(states, adjust.getState())) {
                                available.compareAndSet(available.get(), available.get().add(adjustItem.getAdjustAmount()));
                            }
                        } else {
                            // 减金额
                            String[] states = {
                                    ExpenditureAdjustmentState.submit.getKey(),
                                    ExpenditureAdjustmentState.pass.getKey(),
                            };
                            if (ArrayUtil.contains(states, adjust.getState())) {
                                available.compareAndSet(available.get(), available.get().add(adjustItem.getAdjustAmount()));
                            }
                        }
                        if (last == null || last.getUpdateTime().before(adjustItem.getUpdateTime())) {
                            last = adjustItem;
                        }
                    }
                }
                if (last != null && last.getFluctuate() != null) {
                    fluctuate = last.getFluctuate();
                }
            }
        }
        log.info("available value2:" + available.get());

        if (useFluctuate) {
            log.info("fluctuate:" + fluctuate);
            BigDecimal real = available.get().multiply(BigDecimal.ONE.add(fluctuate.divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP)));
            available.compareAndSet(available.get(), real);
        }
        log.info("available value3:" + available.get());

        final AtomicReference<BigDecimal> sub1 = new AtomicReference<>(BigDecimal.ZERO);// 所有未完成申请单金额
        final AtomicReference<BigDecimal> sub2 = new AtomicReference<>(BigDecimal.ZERO);// 所有未关联申请单的报账金额
        final AtomicReference<BigDecimal> sub3 = new AtomicReference<>(BigDecimal.ZERO);// 所有关联完成的申请单的报账金额
        ExpenditureApplicationDto c1 = new ExpenditureApplicationDto();
        c1.setExpenditureKpiId(dto.getId());
        c1.setExpenditureEconomicId(item.getExpenditureEconomicId());
        List<ExpenditureApplicationDto> eads = expenditureApplicationService.list(c1);
        // 记录未完成的申请单的ID
        CopyOnWriteArrayList<Long> completedAppIds = new CopyOnWriteArrayList<>();
        CollUtil.forEach(eads, (CollUtil.Consumer<ExpenditureApplicationDto>) (value, idx) -> {
            //0保存、1提交审批、2审批通过、3审批驳回、4撤回、5完成
            String[] states1 = {
                    ExpenditureApplicationState.submit.getKey(),
                    ExpenditureApplicationState.pass.getKey(),
            };
            if (ArrayUtil.contains(states1, value.getState())) {
                sub1.compareAndSet(sub1.get(), sub1.get().add(value.getAmount()));
            }
            String[] states2 = {
                    ExpenditureApplicationState.complete.getKey(),
            };
            if (ArrayUtil.contains(states2, value.getState())) {
                completedAppIds.add(value.getId());
            }
        });

        ExpenditureReimbursementDto c2 = new ExpenditureReimbursementDto();
        c2.setExpenditureKpiId(dto.getId());
        c2.setExpenditureEconomicId(item.getExpenditureEconomicId());
        List<ExpenditureReimbursementDto> erds = expenditureReimbursementService.list(c2);
        CollUtil.forEach(erds, (CollUtil.Consumer<ExpenditureReimbursementDto>) (value, idx) -> {
            //0保存、1提交审批、2审批通过、3审批驳回、4撤回、7完成、5支付中、6确认付款
            String[] states = {
                    ExpenditureReimbursementState.submit.getKey(),
                    ExpenditureReimbursementState.pass.getKey(),
                    ExpenditureReimbursementState.complete.getKey(),
                    ExpenditureReimbursementState.paying.getKey(),
                    ExpenditureReimbursementState.confirm.getKey(),
            };
            if (ArrayUtil.contains(states, value.getState())) {
                if (value.getExpenditureApplicationId() == null) {
                    sub2.compareAndSet(sub2.get(), sub2.get().add(value.getAmount()));
                }
                if (value.getExpenditureApplicationId() != null
                        && CollUtil.contains(completedAppIds, value.getExpenditureApplicationId())) {
                    sub3.compareAndSet(sub3.get(), sub3.get().add(value.getAmount()));
                }
            }
        });
        log.info("sub1(未完成的申请单金额):" + sub1);
        log.info("sub2(未关联申请单的报账金额):" + sub2);
        log.info("sub3(已关联完成申请单的报账金额):" + sub3);
        BigDecimal avail = available.get().subtract(sub1.get()).subtract(sub2.get()).subtract(sub3.get());
        available.compareAndSet(available.get(), avail);
        log.info("available value4:" + available.get());
        return available.get();
    }

    @Transactional
    @Override
    public void callbackAfterApprove(Long businessId, boolean isPass, boolean isFinalPass) {
        if (businessId == null)
            return;
        if (isPass) {
            if (isFinalPass) {
                ExpenditureKpiDto ead = this.getById(businessId);
                ead.setState(ExpenditureKpiState.pass.getKey());
                this.updateById(ead);
            }
        } else {
            ExpenditureKpiDto ead = this.getById(businessId);
            ead.setState(ExpenditureKpiState.reject.getKey());
            this.updateById(ead);
        }
    }
}
